/*
 * Copyright 2011 Michael Nitsche
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.abcsolutions.g5.net.tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;

import de.abcsolutions.g5.base.event.A_HasListeners;
import de.abcsolutions.g5.base.event.I_Listener;

/**
 * @author Michael Nitsche
 * 21.01.2010	Erstellt
 * 02.03.2011	Converted to G5
 *
 * TODO Bei Abbruch der Verbindung wartet der Server ewig!
 */
public class TCP_Connection extends A_HasListeners {

	public static final boolean DEBUG=true;
	private enum EVENT { DATA, EXCEPTION };
	private final Socket socket;
	private final InputStream in;
	private final OutputStream out;
	private final BufferedReader bin;
	private final PrintWriter bout;


	public TCP_Connection(Socket socket, boolean event_in) throws IOException {
		if(socket==null)
			throw new NullPointerException();
		this.socket=socket;
		this.socket.setSoTimeout(60000); //Könnte ein Problem sein, wenn der Server kurzzeitig nicht erreichbar ist!
		in  = socket.getInputStream();
		out = socket.getOutputStream();
		bin =new BufferedReader(new InputStreamReader(in));
		bout=new PrintWriter(out);

		if(event_in) {
			Runnable run=new Runnable() {
				public void run() {
					String z=null;
					try {
						while((z=bin.readLine()) !=null)
							listenerStart(EVENT.DATA, z);
					}
					catch(SocketException e) {
						System.out.println("Lost connection!");
						e.printStackTrace();
						return;
					}
					catch(IOException e) {
						listenerStart(EVENT.EXCEPTION, e);
						e.printStackTrace();
					}
				}
			};
			Thread t=new Thread(run);
			t.start();
		}
	}


	public void close() {
		try {
			if(!this.socket.isClosed())
				this.socket.setSoTimeout(1);
			bin.close();
			bout.close();
//			in.close();
//			out.close();
			this.socket.close();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("Verbindung beendet!");
	}

	/**
	 * ACHTUNG! Zeilenumbrüche werden entfernt
	 */
	public void send(String s) throws IOException {
		s=s.replace("\n", ""); //Das ist wichtig, da mit ReadLine empfangen wird! Dies kann aber den Text verfälschen!!!
		if(DEBUG)
			System.out.println("> "+s);
//		bout.write(s);
		bout.println(s);
		bout.flush();
	}

	public String receive() throws IOException {
		try {
			String s=bin.readLine();
			if(DEBUG)
				System.out.println("< "+s);
			return s;
		}
		catch(SocketException e) {
			e.printStackTrace();
			System.out.println("Lost connection!");
		}
		catch(IOException e) {
			e.printStackTrace();
			listenerStart(EVENT.EXCEPTION, e);
		}
		return null;
	}

	/**
	 * Prüft, ob auch wirklich der entsprechende String empfangen wird
	 */
	public boolean receive(String s) throws IOException {
		String e=receive();
		boolean ok= e!=null && s!=null && e.equals(s);
		if(!ok) {
			System.out.println(s+" <---> "+e);
			throw new IOException("Expected: "+s+"\nReceived: "+e);
		}
		return ok;

	}

	public void addListenerData(I_Listener<String> l) {
		listenerAdd(EVENT.DATA, l);
	}

	public void addListenerException(I_Listener<IOException> l) {
		listenerAdd(EVENT.EXCEPTION, l);
	}

	public boolean isConnected() {
		return this.socket!=null && this.socket.isBound() && !this.socket.isClosed(); //TODO Test!
	}

}
